package b.utils.entity

import akka.Done
import com.lightbend.lagom.scaladsl.persistence.{AggregateEvent, AggregateEventTag, PersistentEntity, PersistentEntityRef}
import play.api.libs.json.{Format, Json}

import scala.collection.JavaConversions
import scala.concurrent.Future

/**
  * 贲国称 于 2017/1/8 创建。
  */

case class CC事务State(o事务ID: Option[Long] = None, v参与方s: Map[String, Int] = Map.empty[String, Int], v状态: Int = 0) {
  def fTry(v参与方: String): CC事务State = copy(v参与方s = v参与方s + (v参与方 -> 1))

  def fConfirm(v参与方: String): CC事务State = copy(v参与方s = v参与方s + (v参与方 -> 2))

  def fCancel(v参与方: String): CC事务State = copy(v参与方s = v参与方s + (v参与方 -> -1))

  def fCommit: CC事务State = copy(v状态 = 1)

  def fRollback: CC事务State = copy(v状态 = -1)
}

trait T事务Event extends AggregateEvent[T事务Event] {
  override def aggregateTag(): AggregateEventTag[T事务Event] = O事务Event.TAG

  val v事务ID: Long
}

object O事务Event {
  val TAG: AggregateEventTag[T事务Event] = AggregateEventTag[T事务Event]
}

case class CC事务Started(v事务ID: Long, v事务名称: String, v参与方EntitesID: Map[String, String]) extends T事务Event

object CC事务Started {
  implicit val format1: Format[CC事务Started] = Json.format
}

case class CC事务Committed(v事务ID: Long) extends T事务Event

object CC事务Committed {
  implicit val format1: Format[CC事务Committed] = Json.format
}

case class CC事务RolledBack(v事务ID: Long) extends T事务Event

object CC事务RolledBack {
  implicit val format1: Format[CC事务RolledBack] = Json.format
}

case class CC事务参与方Tried(v事务ID: Long, v参与方: String) extends T事务Event

object CC事务参与方Tried {
  implicit val format1: Format[CC事务参与方Tried] = Json.format
}

case class CC事务参与方Confirmed(v事务ID: Long, v参与方: String) extends T事务Event

object CC事务参与方Confirmed {
  implicit val format1: Format[CC事务参与方Confirmed] = Json.format
}

case class CC事务参与方Canceled(v事务ID: Long, v参与方: String) extends T事务Event

object CC事务参与方Canceled {
  implicit val format1: Format[CC事务参与方Canceled] = Json.format
}

case class CC事务(v事务ID: Long, v事务名称: String, v参与方EntitesID: Map[String, Int], v状态: Int) extends T事务Event

trait T事务CommandBase

trait T事务Command extends T事务CommandBase with PersistentEntity.ReplyType[Done] {
  val v事务ID: Long
}

case class CC事务Start(v事务ID: Long, v事务名称: String, v参与方s: Map[String, T事务参与方[_]]) extends T事务Command

case class CC事务参与方Try(v事务ID: Long, v参与方: String) extends T事务Command

case class CC事务参与方Confirm(v事务ID: Long, v参与方: String) extends T事务Command

case class CC事务参与方Cancel(v事务ID: Long, v参与方: String) extends T事务Command

case class CC事务Commit(v事务ID: Long) extends T事务Command

case class CC事务Rollback(v事务ID: Long) extends T事务Command

case class CC事务Get() extends T事务CommandBase with PersistentEntity.ReplyType[Option[CC事务]]

trait T事务参与方[T] {
  val v事务ID: Long
  val entity: PersistentEntityRef[T]

  def f尝试: Future[Done]

  def f确认: Future[Done]

  def f取消: Future[Done]
}

class C事务PersistentEntity extends ACPersistentEntity {

  override type Command = T事务CommandBase
  override type Event = T事务Event
  override type State = CC事务State

  override def initialState: State = CC事务State()

  override def behavior: Behavior = {
    case CC事务State(None, _, 0) => notCreated
    case CC事务State(Some(_), _, 0) => created
    case CC事务State(Some(_), _, 1) => finished
    case CC事务State(Some(_), _, -1) => finished
  }

  private val getCommand = Actions().onReadOnlyCommand[CC事务Get, Option[CC事务]] {
    case (CC事务Get(), ctx, state) =>
      if (state.o事务ID.isDefined) {
        val v事务 = CC事务(state.o事务ID.get, "?", state.v参与方s, state.v状态)
        ctx.reply(Some(v事务))
      } else ctx.reply(None)
  }

  private val notCreated = {
    Actions().onCommand[CC事务Start, Done] {
      case (cmd: CC事务Start, ctx, state) =>
        val v参与方EntitiesID = cmd.v参与方s map { p => p._1 -> p._2.entity.entityId }
        val event = CC事务Started(cmd.v事务ID, cmd.v事务名称, v参与方EntitiesID)
        ctx.thenPersist(event)(_ => ctx.reply(Done))
    }.onEvent {
      case (event: CC事务Started, _) => CC事务State(Some(event.v事务ID))
    }.orElse(getCommand)
  }

  private val created = {
    Actions()
      .onCommand[CC事务参与方Try, Done] {
      case (cmd: CC事务参与方Try, ctx, _) =>
        ctx.thenPersist(CC事务参与方Tried(cmd.v事务ID, cmd.v参与方))(_ => ctx.reply(Done))
    }.onCommand[CC事务参与方Confirm, Done] {
      case (cmd: CC事务参与方Confirm, ctx, _) =>
        ctx.thenPersist(CC事务参与方Confirmed(cmd.v事务ID, cmd.v参与方))(_ => ctx.reply(Done))
    }.onCommand[CC事务参与方Cancel, Done] {
      case (cmd: CC事务参与方Cancel, ctx, _) =>
        ctx.thenPersist(CC事务参与方Canceled(cmd.v事务ID, cmd.v参与方))(_ => ctx.reply(Done))
    }.onCommand[CC事务Commit, Done] {
      case (cmd: CC事务Commit, ctx, _) =>
        ctx.thenPersist(CC事务Committed(cmd.v事务ID))(_ => ctx.reply(Done))
    }.onCommand[CC事务Rollback, Done] {
      case (cmd: CC事务Rollback, ctx, _) =>
        ctx.thenPersist(CC事务RolledBack(cmd.v事务ID))(_ => ctx.reply(Done))
    }.onEvent {
      case (_: CC事务Committed, state) => state.fCommit
      case (_: CC事务RolledBack, state) => state.fRollback
      case (event: CC事务参与方Tried, state) => state.fTry(event.v参与方)
      case (event: CC事务参与方Confirmed, state) => state.fConfirm(event.v参与方)
      case (event: CC事务参与方Canceled, state) => state.fCancel(event.v参与方)
    }.orElse(getCommand)
  }

  private val finished = {
    Actions()
      .onCommand[CC事务参与方Try, Done](f命令Done)
      .onCommand[CC事务参与方Confirm, Done](f命令Done)
      .onCommand[CC事务参与方Cancel, Done](f命令Done)
      .onCommand[CC事务Commit, Done](f命令Done)
      .onCommand[CC事务Rollback, Done](f命令Done)
      .orElse(getCommand)
  }

}
